/*
 *  PreferencesWindow.cpp
 *  mediTock
 *
 *  Created by tjmitche on 07/04/2009.
 *  Copyright 2009 __MyCompanyName__. All rights reserved.
 *
 */

#include "PreferencesWindow.h"

PreferencesWindow::PreferencesWindow()
:   
// Initialise the base 'DialogWindow'...
DialogWindow(
				T("Preferences"),				// Set the text to use for the title
				Colours::ivory,					// Set the colour of the window
				true,							// Escape key closes window
				true							// This window should be added to the desktop
				)
{
	setContentComponent(preferencesComponent = new PreferencesComponent());
    setResizable (false, false); // resizability is a property of ResizableWindow, which is
	
	setTitleBarHeight (20);      // Set the height of the titlebar on our window.
	windowVisible = false;
	
}

PreferencesWindow::~PreferencesWindow()
{
	setContentComponent (0, true);
	
}

void PreferencesWindow::closeButtonPressed()
{
	//Hide the window here?
	makeVisible(false);
	windowVisible = false;
} 

void PreferencesWindow::startTransport(void)
{
	preferencesComponent->startTransport();
}

void PreferencesWindow::stopTransport(void)
{
	preferencesComponent->stopTransport();
}

int PreferencesWindow::getPreTimeInSeconds(void)
{
	return preferencesComponent->getPreTimeInSeconds();
}
int PreferencesWindow::getTimeInSeconds(void)
{
	return preferencesComponent->getTimeInSeconds();
}

void PreferencesWindow::setTimerInSeconds(int timeSeconds)
{
		preferencesComponent->setTimerInSeconds(timeSeconds);
}

bool PreferencesWindow::preferencesChanged (void)
{
	return preferencesComponent->preferencesChanged();
}

void PreferencesWindow::makeVisible (bool setVal)
{
	setVisible(setVal);
	windowVisible = setVal;
}

bool PreferencesWindow::keyPressed (const KeyPress& key, Component* originatingComponent)
{
	if(key.getKeyCode() == KeyPress::escapeKey)
	{
		makeVisible(false);
		return true;
	}
	return false;
}

//========================================================
PreferencesComponent::PreferencesComponent() : currentAudioFileSource(NULL), slidersChanged(true)
{
	AudioFormatManager formatManager;
	formatManager.registerBasicFormats();
	formatManager.registerFormat(new QuickTimeAudioFormat(), false);
	
	//Prefs window	
	//this now appears in a subwindow - should probably be moved into seperate class?
	
	propertiesFile = PropertiesFile::createDefaultAppPropertiesFile (T("mediTock"),
																	 T("settings"),
																	 String::empty,
																	 false, 3000,
																	 PropertiesFile::storeAsXML);
		
	addAndMakeVisible(instructionsLabel = new Label(T("instructionsLabel"), 
													T("mediTock v0.5\n=========\ntop button - start/stop \nbottom button - reset\n")));
	instructionsLabel->setJustificationType(Justification::centredTop);
	instructionsLabel->setFont(20);
	
	addAndMakeVisible(authorLabel = new Label(T("authorLabel"), 
													T("by tom mitchell")));
	
	addAndMakeVisible(fileLabel = new Label(T("fileLabel"), T("choose an audio file")));
	fileLabel->setJustificationType(Justification::left);
	
	addAndMakeVisible(fileChooser = new FilenameComponent (	T("audiofile"),
										 File::nonexistent,
										 true, false, false,
										 formatManager.getWildcardForAllFormats(),
										 String::empty,
										 T("(choose a file to play)")));
	
	fileChooser->addListener (this);
	
	addAndMakeVisible(playButton = new TextButton (T("play"),T("click here to play the current audio file")));
	playButton->addButtonListener (this);
	playButton->setColour (TextButton::buttonColourId, Colours::lightgreen);
	playButton->setColour (TextButton::buttonOnColourId, Colours::lightgreen);
	playButton->setConnectedEdges (Button::ConnectedOnRight | Button::ConnectedOnLeft);
	
	addAndMakeVisible(stopButton = new TextButton (T("stop"), T("click here to play the current audio file")));
	stopButton->addButtonListener (this);
	stopButton->setColour (TextButton::buttonColourId, Colours::red);
	stopButton->setColour (TextButton::buttonOnColourId, Colours::red);
	stopButton->setConnectedEdges (Button::ConnectedOnLeft);

	addAndMakeVisible(audioSettingsButton = new TextButton (T("audio settings..."),
										  T("click here to change the audio device settings")));
	audioSettingsButton->addButtonListener (this);
	audioSettingsButton->setConnectedEdges (Button::ConnectedOnRight);
	
	addAndMakeVisible(preTimerLabel = new Label(T("preTimerLabel"), T("Lead in time")));
	addAndMakeVisible(preMinutesSlider = new Slider (T("preMinutes")));
	addAndMakeVisible(preSecondsSlider = new Slider (T("preSeconds")));
	addAndMakeVisible(hoursSlider = new Slider (T("hours")));
	addAndMakeVisible(minutesSlider = new Slider (T("minutes")));
	addAndMakeVisible(secondsSlider = new Slider (T("seconds")));
	
	preMinutesSlider->addListener(this);
	preSecondsSlider->addListener(this);
	hoursSlider->addListener(this);
	minutesSlider->addListener(this);
	secondsSlider->addListener(this);
	
	preMinutesSlider->setRange (0, 59, 1);
	preMinutesSlider->setPopupMenuEnabled (true);
	preMinutesSlider->setValue ((propertiesFile->getValue(T("preMinutesSlider"), T("0"))).getIntValue(), false, false);
	preMinutesSlider->setSliderStyle (Slider::IncDecButtons);
    preMinutesSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
    preMinutesSlider->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
	preMinutesSlider->setTextValueSuffix (T("m"));
	
	preSecondsSlider->setRange (0, 59, 1);
	preSecondsSlider->setPopupMenuEnabled (true);
	preSecondsSlider->setValue ((propertiesFile->getValue(T("preSecondsSlider"), T("20"))).getIntValue(), false, false);
	preSecondsSlider->setSliderStyle (Slider::IncDecButtons);
    preSecondsSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
    preSecondsSlider->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
	preSecondsSlider->setTextValueSuffix (T("s"));
	
	addAndMakeVisible(timerLabel = new Label(T("timerLabel"), T("Meditation time")));
	hoursSlider->setRange (0, 24, 1);
	hoursSlider->setPopupMenuEnabled (true);
	hoursSlider->setValue ((propertiesFile->getValue(T("hoursSlider"), T("0"))).getIntValue(), false, false);
	hoursSlider->setSliderStyle (Slider::IncDecButtons);
    hoursSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
    hoursSlider->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
	hoursSlider->setTextValueSuffix (T("h"));
	
	minutesSlider->setRange (0, 59, 1);
	minutesSlider->setPopupMenuEnabled (true);
	minutesSlider->setValue ((propertiesFile->getValue(T("minutesSlider"), T("20"))).getIntValue(), false, false);
	minutesSlider->setSliderStyle (Slider::IncDecButtons);
    minutesSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
    minutesSlider->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
	minutesSlider->setTextValueSuffix (T("m"));
	
	secondsSlider->setRange (0, 59, 1);
	secondsSlider->setPopupMenuEnabled (true);
	secondsSlider->setValue ((propertiesFile->getValue(T("secondsSlider"), T("0"))).getIntValue(), false, false);
	secondsSlider->setSliderStyle (Slider::IncDecButtons);
    secondsSlider->setTextBoxStyle (Slider::TextBoxLeft, false, 50, 20);
    secondsSlider->setIncDecButtonsMode (Slider::incDecButtonsDraggable_Vertical);
	secondsSlider->setTextValueSuffix (T("s"));
	
	//==============================================================================
	// register for start/stop messages from the transport source..
	transportSource.addChangeListener(this);
	
	// and initialise the device manager with no settings so that it picks a
	// default device to use.
	
	const String error (audioDeviceManager.initialise (1, /* number of input channels */
													   2, /* number of output channels */
													   0, /* no XML settings.. */
													   true  /* select default device on failure */));
	
	if (error.isNotEmpty())
	{
		AlertWindow::showMessageBox (AlertWindow::WarningIcon,
									 T("Audio Demo"),
									 T("Couldn't open an output device!\n\n") + error);
	}
	else
	{
		// add the two audio sources to our mixer..
		mixerSource.addInputSource (&transportSource, false);
		// ..and connect the mixer to our source player.
		audioSourcePlayer.setSource (&mixerSource);
		
		// start the IO device pulling its data from our callback..
		audioDeviceManager.setAudioCallback (this);
		//everything is ready try to load file
		fileChooser->setCurrentFile (File(propertiesFile->getValue(T("audioFile"), File::getCurrentWorkingDirectory().getFullPathName()+T("/zenergy.aif"))), true); 
	}
}

PreferencesComponent::~PreferencesComponent()
{
	stopButton->removeButtonListener(this);
	audioSettingsButton->removeButtonListener (this);
	playButton->removeButtonListener (this);
	fileChooser->removeListener(this);
	
	audioDeviceManager.setAudioCallback (0);
	
	//transportSource.removeChangeListener (this);//I don't know if these are really necessary
	
	transportSource.setSource (0);
	if(currentAudioFileSource)
		deleteAndZero (currentAudioFileSource);
	
	audioSourcePlayer.setSource (0);
	
	
}

void PreferencesComponent::resized ()
{
	// This is called whenever this component's size changes. We could respond
	// to this in a number of ways, but the most obvious thing to do is reposition
	// all our widgets, using their 'setBounds()' function.
	// It's nice to position them relative to the size of this Component. That means
	// making use of the 'getWidth()' and 'getHeight()' functions to determine where
	// to put them and how big they should be.
	
	unsigned int width = getWidth();
	
	instructionsLabel->setBounds(10, 10, width-20, 100);
	
	fileLabel->setBounds(10, 170, (int)(0.8* (width-20)), 20);
	playButton->setBounds(width-110, 170, 50, 20);
	stopButton->setBounds(width-60, 170, 50, 20);
	fileChooser->setBounds(10, 193, width-20, 20);
	audioSettingsButton->setBounds(width-210, 170, 100, 20);
	audioSettingsButton->changeWidthToFitText();
	
	authorLabel->setBounds(width-107, 220, 100, 20);
	
	preTimerLabel->setBounds(10, 100, 100, 20);
	preMinutesSlider->setBounds(110, 100, 100, 20);
	preSecondsSlider->setBounds(210, 100, 100, 20);
	
	timerLabel->setBounds(10, 130, 100, 20);
	hoursSlider->setBounds(110, 130, 100, 20);
	minutesSlider->setBounds(210, 130, 100, 20);
	secondsSlider->setBounds(310, 130, 100, 20);
	
	updateButtons();
}

void PreferencesComponent::buttonClicked (Button* button) 
{ 
	//callback for button pressess
	if (button == playButton)
	{
		transportSource.setPosition (0.0);
		transportSource.start();
	}
	else if (button == stopButton)
	{
		transportSource.stop();
	}
	else if (button == audioSettingsButton)
	{
		// Create an AudioDeviceSelectorComponent which contains the audio choice widgets...
		
		AudioDeviceSelectorComponent audioSettingsComp (audioDeviceManager,
														0, 0,
														2, 2,
														false,
														false,
														true,
														true);
		
		// ...and show it in a DialogWindow...
		audioSettingsComp.setSize (500, 450);
		
		DialogWindow::showModalDialog (T("Audio Settings"),
									   &audioSettingsComp,
									   this,
									   Colours::azure,
									   true);
	}
	
	
} 


void PreferencesComponent::changeListenerCallback (void*)
{
	// callback from the transport source to tell us that play has
	// started or stopped, so update our buttons..
	updateButtons();
}


void PreferencesComponent::filenameComponentChanged (FilenameComponent*)
{
	// this is called when the user changes the filename in the file chooser box
	
	File audioFile (fileChooser->getCurrentFile());
	
	//save the file pathname in the properties file
	propertiesFile->setValue(T("audioFile"), audioFile.getFullPathName());
	
	// unload the previous file source and delete it..
	transportSource.stop();
	transportSource.setSource (0);
	deleteAndZero (currentAudioFileSource);
	
	// create a new file source from the file..
	
	// get a format manager and set it up with the basic types (wav and aiff).
	AudioFormatManager formatManager;
	formatManager.registerBasicFormats();
	formatManager.registerFormat(new QuickTimeAudioFormat, false);//mp3 support
	
	AudioFormatReader* reader = formatManager.createReaderFor (audioFile);
	
	if (reader != 0)
	{
		
		currentFile = audioFile;
		
		currentAudioFileSource = new AudioFormatReaderSource (reader, true);
		
		// ..and plug it into our transport source
		transportSource.setSource (currentAudioFileSource,
								   32768, // tells it to buffer this many samples ahead
								   reader->sampleRate);
	}
	else
	{
		AlertWindow::showMessageBox (AlertWindow::WarningIcon,
									 T("mediTock Audio File Error"),
									 T("No audio file loaded. Select an alarm sound from the mediTock->preferences menu."),
									 T("ok"));
	}
	
	updateButtons();
}


void PreferencesComponent::updateButtons()
{
	playButton->setEnabled (currentAudioFileSource != 0 && ! transportSource.isPlaying());
	stopButton->setEnabled (transportSource.isPlaying());
}


void PreferencesComponent::audioDeviceIOCallback (const float** inputChannelData,
										   int totalNumInputChannels,
										   float** outputChannelData,
										   int totalNumOutputChannels,
										   int numSamples)
{
	// pass the audio callback on to our player source, and also the waveform display comp
	audioSourcePlayer.audioDeviceIOCallback (inputChannelData, totalNumInputChannels, outputChannelData, totalNumOutputChannels, numSamples);
}

void PreferencesComponent::audioDeviceAboutToStart (AudioIODevice* device)
{
	audioSourcePlayer.audioDeviceAboutToStart (device);
}

void PreferencesComponent::audioDeviceStopped()
{
	audioSourcePlayer.audioDeviceStopped();
}

void PreferencesComponent::startTransport(void)
{
	transportSource.setPosition (0.0);
	transportSource.start();
}

void PreferencesComponent::stopTransport(void)
{
	transportSource.stop();
}

int PreferencesComponent::getPreTimeInSeconds(void)
{
	return (int)(preSecondsSlider->getValue() + preMinutesSlider->getValue()*60);
	
}

int PreferencesComponent::getTimeInSeconds(void)
{
	return (int)(secondsSlider->getValue() + minutesSlider->getValue()*60 + hoursSlider->getValue()*60*60);
}

void PreferencesComponent::setTimerInSeconds(int timeSeconds)
{
	if(timeSeconds<0)
		timeSeconds = 0;
	secondsSlider->setValue(timeSeconds % 60, false, false);
	minutesSlider->setValue((timeSeconds/60)%60, false, false);
	hoursSlider->setValue((timeSeconds/60/60)%24, false, false);
	
	propertiesFile->setValue(T("secondsSlider"), String(secondsSlider->getValue()));
	propertiesFile->setValue(T("minutesSlider"), String(minutesSlider->getValue()));
	propertiesFile->setValue(T("hoursSlider"), String(hoursSlider->getValue()));
	
}

void PreferencesComponent::sliderValueChanged (Slider* slider) //this will be set to false when preferencesChanged is called 
{
	slidersChanged = true;
	if(slider == preSecondsSlider)
		propertiesFile->setValue(T("preSecondsSlider"), String(preSecondsSlider->getValue()));
	else if(slider == preMinutesSlider)
		propertiesFile->setValue(T("preMinutesSlider"), String(preMinutesSlider->getValue()));
	else if(slider == secondsSlider)
		propertiesFile->setValue(T("secondsSlider"), String(secondsSlider->getValue()));
	else if(slider == minutesSlider)
		propertiesFile->setValue(T("minutesSlider"), String(minutesSlider->getValue()));
	else if(slider == hoursSlider)
		propertiesFile->setValue(T("hoursSlider"), String(hoursSlider->getValue()));

}

void PreferencesComponent::updateSliderValues()
{
	propertiesFile->setValue(T("secondsSlider"), String(secondsSlider->getValue()));
	propertiesFile->setValue(T("minutesSlider"), String(minutesSlider->getValue()));
	propertiesFile->setValue(T("hoursSlider"), String(hoursSlider->getValue()));
}

bool PreferencesComponent::preferencesChanged (void)  
{
	bool retval = slidersChanged;
	slidersChanged = false;
	return retval;
}






